#include "ano.h"
#include "main.h"
#include "string.h"
#include "stdio.h"
#if defined   (__CC_ARM) /*!< ARM Compiler */
#pragma O0
#elif defined (__GNUC__) /*!< GNU Compiler */
#pragma GCC optimize ("O0")
#endif /* __CC_ARM */
/*发送的代码好像不能开优化*/

/*定义全局数据发送结构体,需要监测的与发送的飞控常规数据放进这里面*/
Ano_V8_t Ano_V8 = {0};

/**********下方为命令与参数的定义列表****************/
/**命令列表 命令0*/
cmd_c2_t cmd_c2_g0 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xc2,
    .head.len0 = (12 + 20 + 30),
    .head.len1 = 0,

    .cmd_id = 0,
    .cmd_c0_v.cid0 = 0,
    .cmd_c0_v.cid1 = 0,
    .cmd_c0_v.cid2 = 0,

    .cmd_c0_v.val0 = 9, // float 型
    .cmd_c0_v.val1 = 9, // float 型
    .cmd_c0_v.val2 = 9, // float 型
    .cmd_c0_v.val3 = 0,
    .cmd_c0_v.val4 = 0,
    .cmd_c0_v.val5 = 0,
    .cmd_c0_v.val6 = 0,
    .cmd_c0_v.val7 = 0, // 无参数
    .cmd_name = {"PID"},
    .cmd_info = {"val0=Kp val1=Ki  val2=Kd"},
};


 
/**命令列表开始**/
/** 命令1 */
cmd_c2_t cmd_c2_g1 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xc2,
    .head.len0 = (12 + 20 + 50),
    .head.len1 = 0,

    .cmd_id = 1,
    .cmd_c0_v.cid0 = 1,
    .cmd_c0_v.cid1 = 0,
    .cmd_c0_v.cid2 = 0,

    .cmd_c0_v.val0 = 9, // float 型
    .cmd_c0_v.val1 = 9, // float 型
    .cmd_c0_v.val2 = 9, // float 型
    .cmd_c0_v.val3 = 0,
    .cmd_c0_v.val4 = 0,
    .cmd_c0_v.val5 = 0,
    .cmd_c0_v.val6 = 0,
    .cmd_c0_v.val7 = 0, // 无参数
    .cmd_name = {"Set Target"},
    .cmd_info = {"All parameters are float"},
};

/** 命令2 */
cmd_c2_t cmd_c2_g2 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xc2,
    .head.len0 = (12 + 20 + 50),
    .head.len1 = 0,

    .cmd_id = 2,        // 请按照顺序增加
    .cmd_c0_v.cid0 = 2, // 记得每个命令的不一样 最好按照顺序
    .cmd_c0_v.cid1 = 0,
    .cmd_c0_v.cid2 = 0,

    .cmd_c0_v.val0 = 1,
    .cmd_c0_v.val1 = 1,
    .cmd_c0_v.val2 = 1,
    .cmd_c0_v.val3 = 0,
    .cmd_c0_v.val4 = 0,
    .cmd_c0_v.val5 = 0,
    .cmd_c0_v.val6 = 0,
    .cmd_c0_v.val7 = 0, // 无参数
    .cmd_name = {"key"},
    .cmd_info = {"  val0=open or off val1=sleep val2=emergency stop"},
};

/** * 命令列表 命令3 */
cmd_c2_t cmd_c2_g3 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xc2,
    .head.len0 = (12 + 20 + 50),
    .head.len1 = 0,

    .cmd_id = 3,
    .cmd_c0_v.cid0 = 3,
    .cmd_c0_v.cid1 = 0,
    .cmd_c0_v.cid2 = 0,

    .cmd_c0_v.val0 = 1,
    .cmd_c0_v.val1 = 1,
    .cmd_c0_v.val2 = 1,
    .cmd_c0_v.val3 = 0,
    .cmd_c0_v.val4 = 0,
    .cmd_c0_v.val5 = 0,
    .cmd_c0_v.val6 = 0,
    .cmd_c0_v.val7 = 0, // 无参数
    .cmd_name = {"key1"},
    .cmd_info = {"val0=open or off val1=sleep val2=emergency stop"},
};
/**命令列表结束**/


struct cmd_g0
{
   float val0;
   float val1;
   float val2;
}cmd_c0_g0;
struct cmd_g1
{
   float val0;
   float val1;
   float val2;
}cmd_c0_g1;
struct cmd_g2
{
   uint8_t val0;
   uint8_t val1;
   uint8_t val2;
}cmd_c0_g2;

struct cmd_g3
{
   uint8_t val0;
   uint8_t val1;
   uint8_t val2;
}cmd_c0_g3;

/**参数列表开始**/
/* 参数值本身 */

//全局参数g0
//用途:未知
parameter_rw_t parameter_rw_g0 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe1,
    .head.len0 = (6), // float型 4字节+uint16_t型 2字节
    .head.len1 = 0,
    .par_id = 0x0000,
    .val = 0.1f,
};

parameter_rw_t parameter_rw_g1 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe1,
    .head.len0 = (6), // float型 4字节+uint16_t型 2字节
    .head.len1 = 0,
    .par_id = 0x0001,
    .val = 0.2f,
};
parameter_rw_t parameter_rw_g2 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe1,
    .head.len0 = (6), // float型 4字节+uint16_t型 2字节
    .head.len1 = 0,
    .par_id = 0x0002,
    .val = 0.3f,
};
/*参数列表结束**/

/*设置参数信息*/
parameter_back_t parameter_back_g0 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe2,
    .head.len0 = (3 + 20 + 20),
    .head.len1 = 0,
    .par_id = 0x0000,
    .par_type = 0x08,
    .par_name = {"par0"},
    .par_info = {"par 0 info"},
};
parameter_back_t parameter_back_g1 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe2,
    .head.len0 = (3 + 20 + 20),
    .head.len1 = 0,
    .par_id = 0x0001,
    .par_type = 0x08,
    .par_name = {"par1"},
    .par_info = {"par 1 info"},
};
parameter_back_t parameter_back_g2 = {
    .head.head = 0xab,
    .head.s_addr = LOCA_ID,   // 代表本机为飞控
    .head.d_addr = TARGET_ID, // 发送目的为上位机
    .head.id = 0xe2,
    .head.len0 = (3 + 20 + 20),
    .head.len1 = 0,
    .par_id = 0x0002,
    .par_type = 0x08,
    .par_name = {"par2"},
    .par_info = {"par 2 info"},
};

/*命令与参数的定义区域结束 在定义完成之后,需要将其地址存入下方的数组中以备调用 记得在头文件修改参数数量 否则无法过校验*/

/*命令地址集合*/
uint8_t *cmd_c2_collection[cmd_number] = {(uint8_t *)&cmd_c2_g0, (uint8_t *)&cmd_c2_g1, (uint8_t *)&cmd_c2_g2, (uint8_t *)&cmd_c2_g3};
/*命令值地址集合*/
uint8_t *cmd_c0_collection[cmd_number] = {(uint8_t *)&cmd_c0_g0, (uint8_t *)&cmd_c0_g1, (uint8_t *)&cmd_c0_g2, (uint8_t *)&cmd_c0_g3};
/*参数数据地址集合*/
uint8_t *cmd_e1_collection[param_number] = {(uint8_t *)&parameter_rw_g0, (uint8_t *)&parameter_rw_g1, (uint8_t *)&parameter_rw_g2};
/*参数信息设置地址集合*/
uint8_t *cmd_e2_collection[param_number] = {(uint8_t *)&parameter_back_g0, (uint8_t *)&parameter_back_g1, (uint8_t *)&parameter_back_g2};

/**
 * 匿名数据发送校验赋值
 */
static void ano_check(void *arg)
{
    uint8_t sumcheck = 0;
    uint8_t addcheck = 0;
    uint8_t *len = arg;
    uint8_t lens, len0, len1;
    len0 = *(len + 4);
    len1 = *(len + 5);
    lens = len0 + len1 * 256;
    for (uint16_t i = 0; i < lens + 6; i++)
    {
        sumcheck += *(len + i);
        addcheck += sumcheck;
    }
    *(len + lens + 6) = sumcheck;
    *(len + lens + 7) = addcheck;
}

/// @brief 输出性数据的发送,填入本次要发送的数据地址
/// @param arg 发送缓冲结构体数据地址
/// @param target 需要发送的数据结构体地址
/// @return
static HAL_StatusTypeDef presend(uint8_t *arg, void *target)
{
    uint16_t time_out = 0;
    uint8_t lens, len0, len1;
    len0 = *(arg + 4);
    len1 = *(arg + 5);
    lens = len0 + len1 * 256;
    memcpy((arg + 6), (target + 6), lens);
    ano_check(arg);
    while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)arg, lens + 8))
    {
        time_out++;
        if (time_out >= 0xffff)
        {
            return HAL_TIMEOUT;
        }
    }
    return HAL_OK;
}

/// @brief 回复C0的校验数据 输入本次接收到的数据帧地址
/// @param arg 本次接收到的数据缓存地址 一般来说就是全局变量 Ano_V8这个结构体;
void ano_callback_check(uint8_t *arg)
{

    uint8_t len = *(arg + 4);                 // 获得数据长度
    Ano_V8.Check_d.id_get = *(arg + 3);       // 获得本次帧ID
    Ano_V8.Check_d.sc_get = *(arg + 6 + len); // 获得和校验
    Ano_V8.Check_d.ac_get = *(arg + 7 + len); // 获得全校验

    Check_t Check_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x00,
        .head.len0 = 3,
        .head.len1 = 0,
        .id_get = Ano_V8.Check_d.id_get,
        .sc_get = Ano_V8.Check_d.sc_get,
        .ac_get = Ano_V8.Check_d.ac_get,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    ano_check(&Check_b);
    while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&Check_b, sizeof(Check_b)))
        ;
    HAL_Delay(1); // 很奇怪的一个问题,似乎是由于出栈与DMA发送之间存在了跳转的问题,增加1ms的延时后就能正常发送出去了;
}

/**
 *匿名数据发送
 */
void ano_send(void)
{

#if Fly_Ctrl_Frames
#ifdef ID01
    // ID:01
    Ins_t Ins_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x01,
        .head.len0 = 13,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Ins_b, &Ano_V8.Ins_d);
#endif
#ifdef ID02
    // ID:02
    Mag_t Mag_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x02,
        .head.len0 = 9,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Mag_b, &Ano_V8.Mag_d);
#endif
#ifdef ID03
    // ID：03
    Angle_t Angle_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x03,
        .head.len0 = 7,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Angle_b, &Ano_V8.Angle_d);
#endif

#ifdef ID04
    Quaternion_t Quaternion_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x04,
        .head.len0 = 9,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&Quaternion_b, &Ano_V8.Quaternion_d);
#endif

#ifdef ID05
    Height_t Height_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x05,
        .head.len0 = 13,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Height_b, &Ano_V8.Height_d);
#endif

#ifdef ID06
    Fc_mode_t Fc_mode_b = {

        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x06,
        .head.len0 = 5,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&Fc_mode_b, &Ano_V8.Fc_mode_d);

#endif

#ifdef ID07
    Speed_t Speed_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x07,
        .head.len0 = 6,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Speed_b, &Ano_V8.Speed_d);
#endif

#ifdef ID08

    Position_Offset_t Position_Offset_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x08,
        .head.len0 = 12,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Position_Offset_b, &Ano_V8.Position_Offset_d);
#endif

#ifdef ID09

    Wind_speed_t Wind_speed_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x09,
        .head.len0 = 4,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    memcpy(&Wind_speed_b.wind_x, &Ano_V8.Wind_speed_d.wind_x, Wind_speed_b.head.len0);
    ano_check(&Wind_speed_b);
    while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&Wind_speed_b, sizeof(Wind_speed_b)))
        ;
#endif

#ifdef ID0a

    tar_att_t tar_att_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0a,
        .head.len0 = 6,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };
    memcpy(&tar_att_b.tar_rol, &Ano_V8.tar_att_d.tar_rol, tar_att_b.head.len0);
    ano_check(&tar_att_b);
    while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&tar_att_b, sizeof(tar_att_b)))
        ;

#endif

#ifdef ID0b

    tar_speed_t tar_speed_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0b,
        .head.len0 = 6,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&tar_speed_b, &Ano_V8.tar_speed_d);
#endif

#ifdef ID0c
    RAD_t RAD_b = {

        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0c,
        .head.len0 = 4,
        .head.len1 = 0,
        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&RAD_b, &Ano_V8.RAD_d);
#endif

#ifdef ID0d

    Vbat_t Vbat_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0d,
        .head.len0 = 4,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&Vbat_b, &Ano_V8.Vbat_d);
#endif

#ifdef ID0e

    extern_moude_sta_t extern_moude_sta_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0e,
        .head.len0 = 4,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,

    };

    presend((uint8_t *)&extern_moude_sta_b, &Ano_V8.extern_moude_sta_d);
#endif

#ifdef ID0f
    bri_rgb_t bri_rgb_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x0f,
        .head.len0 = 4,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };

    presend((uint8_t *)&bri_rgb_b, &Ano_V8.bri_rgb_d);
#endif
#endif

#if Fly_Ctrl_Output_Frames
#ifdef ID20
    // ID0x20
    Pwm_t Pwm_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x20,
        .head.len0 = 16,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Pwm_b, &Ano_V8);

#endif
#ifdef ID21
    att_ctrl_t att_ctrl_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x21,
        .head.len0 = 8,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&att_ctrl_b, &Ano_V8.att_ctrl_d);
#endif
#endif

#if Fly_CtrlRev_CMD_Frames
#ifdef ID40
    // ID:0x40
    Rc_t Rc_b = {
        .head.head = 0xab,
        .head.s_addr = LOCA_ID,   // 代表本机为飞控
        .head.d_addr = TARGET_ID, // 发送目的为上位机
        .head.id = 0x40,
        .head.len0 = 20,
        .head.len1 = 0,

        .tail.sc = 0,
        .tail.ac = 0,
    };
    presend((uint8_t *)&Rc_b, &Ano_V8.Rc_d);
#endif

#endif
#if CMD_Frames
    if (Ano_V8.cmd_flag_d.C0 == 0x01) // 接受相应的命令 并回复命令
    {
        uint16_t cid0 = *(uint8_t *)(Ano_V8.cmd_flag_d.check_arg + 6); // 
        uint16_t cid1 = *(uint8_t *)(Ano_V8.cmd_flag_d.check_arg + 7);
        uint16_t cid2 = *(uint8_t *)(Ano_V8.cmd_flag_d.check_arg + 8);

        /*为了方便只使用了cid0字段的id作为地址的偏移量,实际上应该根据cid0字段的id值来判断是哪个命令*/
        memcpy((uint8_t *)(cmd_c0_collection[cid0]), (Ano_V8.cmd_flag_d.check_arg + 9),12); // 内存拷贝读取参数

        // 参数A=*(val*)(Ano_V8.cmd_flag_d.check_arg+9)对命令进行接收 具体什么数据类型由你的命令参数决定
        /*此处进行命令数据接收解析**/
        ano_callback_check(Ano_V8.cmd_flag_d.check_arg); /*向上位机回复本次的解析情况,调用前要注意是否被赋给本次接受的数据的地址*/
        Ano_V8.cmd_flag_d.C0 = 0x00;
    }

    if (Ano_V8.cmd_flag_d.C1 == 0x01) // 功能帧返回命令数量
    {
        cmd_c1_t cmd_c1_b = {
            .head.head = 0xab,
            .head.s_addr = LOCA_ID,   // 代表本机为飞控
            .head.d_addr = TARGET_ID, // 发送目的为上位机
            .head.id = 0xc1,
            .head.len0 = 3,
            .head.len1 = 0,
            .cmd = 0,
            .val = cmd_number, // 返回命令数量, `cmd_number`个参数
        };

        ano_check(&cmd_c1_b);
        while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&cmd_c1_b, sizeof(cmd_c1_b)))
            ;
        HAL_Delay(1);
        Ano_V8.cmd_flag_d.C1 = 0x00; // 复位
    }

    if (Ano_V8.cmd_flag_d.C2 == 0x01)
    {
        if (Ano_V8.cmd_flag_d.do_it < cmd_number) // ID号码也是我们地址的集合顺序,判断其是属于我们的命令范围
        {
            ano_check(cmd_c2_collection[Ano_V8.cmd_flag_d.do_it]);
            while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)cmd_c2_collection[Ano_V8.cmd_flag_d.do_it], sizeof(cmd_c2_t)))
                ;
        }
        /***照猫画虎的添加你所需要的命令***/

        Ano_V8.cmd_flag_d.C2 = 0x00;
    }

#endif

#if Read_Write_Frames // 消息读写

    if (Ano_V8.cmd_flag_d.E0 == 0x01)
    {
        if (Ano_V8.cmd_flag_d.do_it == 0x02) // 写入参数值操作
        {
            uint16_t id = *(uint16_t *)(Ano_V8.cmd_flag_d.check_arg + 7); // 是针对 E0帧的02操作 进行E1的回复 获取参数ID 指针移动7个字节
            if (id < param_number)
            {
                ano_check(cmd_e1_collection[id]);
                while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)cmd_e1_collection[id], sizeof(parameter_rw_t)))
                    ;
            }

            Ano_V8.cmd_flag_d.do_it = 0; // 执行码清除
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }

        /******************一下是接收到E0消息后的回复*********************/

        if (Ano_V8.cmd_flag_d.do_it == 0xaa) // 参数恢复默认
        {
            /*参数恢复的赋值操作*/
            ANO_RESET_PARA;
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else if (Ano_V8.cmd_flag_d.do_it == 0xab) // TODO:参数保存
        {
            /*操作行为*/
            ANO_SAVE_PARA;//宏命令 进行参数保存操作
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else if (Ano_V8.cmd_flag_d.do_it == 20) // TODO: 清除加速度校准
        {                  
            ANO_CLEAR_ACCEL_CALI;                     /*操作行为*/
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else if (Ano_V8.cmd_flag_d.do_it == 0x21) // TODO: 保存加速度计校准
        {                            
            ANO_SAVE_ACCEL_CALI;             /*操作行为*/
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else if (Ano_V8.cmd_flag_d.do_it == 0x30) // TODO:清除罗盘校准数据
        {                
            ANO_CLEAR_MAG_CALI;                         /*操作行为*/
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else if (Ano_V8.cmd_flag_d.do_it == 0x31) // TODO:保存罗盘校准数据
        {       
            ANO_SAVE_MAG_CALI;                                  /*操作行为*/
            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }
        else // 没有二级操作的话就是告诉上位机又多少个参数
        {
            parameter_cmd_t parameter_cmd_b = {
                .head.head = 0xab,
                .head.s_addr = LOCA_ID,   // 代表本机为飞控
                .head.d_addr = TARGET_ID, // 发送目的为上位机
                .head.id = 0xe0,
                .head.len0 = 3,
                .head.len1 = 0,
                .cmd = 1,
                .val = param_number,
            };
            ano_check(&parameter_cmd_b);
            while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&parameter_cmd_b, sizeof(parameter_cmd_b)))
                ;
        }
        Ano_V8.cmd_flag_d.E0 = 0;
    }

    if (Ano_V8.cmd_flag_d.E1 == 0x01)
    {
        if (Ano_V8.cmd_flag_d.do_it == 0xe1) // 判断是否是需要写入参数 符合验证则为进行参数写入
        {
            uint16_t id = *(uint16_t *)(Ano_V8.cmd_flag_d.check_arg + 6); // 获取参数ID 指针移动6个字节直接就是参数ID

            if (id < param_number)
            {
                // parameter_rw_g0.val = *(float *)(Ano_V8.cmd_flag_d.check_arg + 8); // 读取参数值
                memcpy((uint8_t *)(cmd_e1_collection[id] + 8), (Ano_V8.cmd_flag_d.check_arg + 8), parameter_rw_g0.head.len0 - 2); // 内存拷贝读取参数
                // 拷贝字节的长度就是数据长度-2,因为前面两个字节是参数ID
            }

            Ano_V8.cmd_flag_d.do_it = 0;
            Ano_V8.cmd_flag_d.C0 = 0x01; // 执行校验命令帧
        }

        Ano_V8.cmd_flag_d.E1 = 0x00;
    }

    if (Ano_V8.cmd_flag_d.E2 == 0x01)
    {
        uint16_t id = (uint16_t) * (Ano_V8.cmd_flag_d.check_arg + 7); // 获取参数ID 指针移动7个字节
        if (id < param_number)
        {
            ano_check(cmd_e2_collection[id]); // 指针数组索引到对应命令帧进行回复
            while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)cmd_e2_collection[id], sizeof(parameter_back_t)))
                ;
        }
        Ano_V8.cmd_flag_d.E2 = 0;
    }

    if (Ano_V8.cmd_flag_d.E3 == 0x01)
    {
        info_t info_b = {
            .head.head = 0xab,
            .head.s_addr = LOCA_ID,   // 代表本机为飞控
            .head.d_addr = TARGET_ID, // 发送目的为上位机
            .head.id = 0xe3,
            .head.len0 = (9 + 12),
            .head.len1 = 0,
            .dev_id = LOCA_ID,
            .hw_ver = 0x01,
            .sw_ver = 0x01,
            .bl_ver = 0x01,
            .pt_ver = 0x08,
            .dev_name = {"RoboMaster-C"},
            .tail.sc = 0,
            .tail.ac = 0,
        };
        ano_check(&info_b);
        while (HAL_UART_Transmit_DMA(&ANO_UART, (uint8_t *)&info_b, sizeof(info_b)))
            ;
        Ano_V8.cmd_flag_d.E3 = 0;
    }

#endif

    /*设备升级操作*/
    if (Ano_V8.cmd_flag_d.F0 == 1)
    {
        if (0x01 == *((uint8_t *)Ano_V8.cmd_flag_d.check_arg + 6)) // 是否为固件信息
        {

                boot_jump_to_run(BLaddr);
        }
        //__disable_irq();//关闭全局中断

        /*如果跳转失败 则复位继续程序*/
        Ano_V8.cmd_flag_d.F0 = 0;
        //__enable_irq();//开启全局中断
    }

}



/*
* @brief 命令处理服务函数
* @param arg 接收到的命令数据指针
* @return 无
* @note 此函数在中断中调用,不能做太多的处理
*/
void ano_cmd_rev(uint8_t *arg)
{
    if (*arg == 0xab)
    {

        uint8_t len = (*(arg + 4)) + (*(arg + 5)) * 256; // 获得长度
        uint8_t sc_get = *(arg + 6 + len);               // 获得和校验
        uint8_t ac_get = *(arg + 7 + len);               // 获得全校验

        uint8_t sumcheck_b = 0;
        uint8_t addcheck_b = 0;
        for (uint16_t i = 0; i < (len + 6); i++) // 进行校验
        {
            sumcheck_b += *(arg + i);
            addcheck_b += sumcheck_b;
        }
        if ((sc_get == sumcheck_b) && (ac_get == addcheck_b)) // 校验数据是否通过
        {
            /**********命令处理************************/
            if (*(arg + 3) == 0xc0) // 命令帧对接收的命令进行处理
            {
                Ano_V8.cmd_flag_d.check_arg = arg;
                Ano_V8.cmd_flag_d.do_it = 0xc0; // 命令帧处理
                Ano_V8.cmd_flag_d.C0 = 0x01;
            }
            if (*(arg + 3) == 0xc1)
            {
                if (*(arg + 6) == 0x00) // 返回命令数量
                {
                    Ano_V8.cmd_flag_d.C1 = 0x01; // 返回C1帧 值为命令数量
                }
                if (*(arg + 6) == 0x01) // 返回命令内容
                {
                    Ano_V8.cmd_flag_d.do_it = (*(uint16_t *)(arg + 7));
                    Ano_V8.cmd_flag_d.C2 = 1; // 返回C2帧 赋给命令ID值;为了防止命令码与锁干扰,加上0xF0的偏移
                }
            }

            /***************************************/
            /*********以下为读写参数帧的处理***********/
            if (*(arg + 3) == 0xe0) // 验证信息ID
            {
                if (*(arg + 6) == 0x00) // 读取设备信息 返回ID:E3的数据
                {
                    Ano_V8.cmd_flag_d.E3 = 1; // 发送设备信息 无其余的信息,为触发型
                }
                if (*(arg + 6) == 0x01) // 读取设备命令 返回ID:E0的数据
                {
                    Ano_V8.cmd_flag_d.E0 = 1; // cmd码为1 发送命令数量 触发型
                }
                if (*(arg + 6) == 0x02) // 读取参数值 返回ID:E1的数据
                {
                    Ano_V8.cmd_flag_d.check_arg = arg; // 传入接受数据指针 需要进行E1帧进行二级处理
                    Ano_V8.cmd_flag_d.do_it = 0x02;    // 清除值,执行默认操作:发送参数信息;
                    Ano_V8.cmd_flag_d.E0 = 1;          // 读取参数值,此时VAL为参数ID
                }
                if (*(arg + 6) == 0x03) // 读取参数值 返回ID:E2的数据
                {
                    Ano_V8.cmd_flag_d.check_arg = arg; // 传入接受数据指针 需要进行E2帧进行二级处理
                    Ano_V8.cmd_flag_d.E2 = 1;          // 返回E2帧读取参数信息
                }
                if (*(arg + 6) == 0x10) // 参数命令 返回0x00的校验值
                {

                    Ano_V8.cmd_flag_d.check_arg = arg; // 传递给接收的数据指针
                    if (*(arg + 7) == 0xaa)            // 恢复默认参数
                    {
                        Ano_V8.cmd_flag_d.do_it = 0xaa; // 标记执行码
                    }
                    if (*(arg + 7) == 0xab) // 保存参数命令
                    {
                        Ano_V8.cmd_flag_d.do_it = 0xab;
                    }
                    if (*(arg + 7) == 0x20) // 清除加速度校准数据,校准开始会自动发送本命令确保视窗的数据为传感器的原始数据
                    {
                        Ano_V8.cmd_flag_d.do_it = 0x20;
                    }
                    if (*(arg + 7) == 0x21) // 加速度计校准完成后发送本命令,用于出发参数保存及启用相关功能
                    {
                        Ano_V8.cmd_flag_d.do_it = 0x21;
                    }
                    if (*(arg + 7) == 0x30)
                    {
                        Ano_V8.cmd_flag_d.do_it = 0x30;
                    }
                    if (*(arg + 7) == 0x31)
                    {
                        Ano_V8.cmd_flag_d.do_it = 0x31;
                    }
                    Ano_V8.cmd_flag_d.E0 = 1; // 标记E0命令集进行二级处理
                }
            }
            if (*(arg + 3) == 0xe1) // 写参数(先读命令列表才能写入)
            {

                Ano_V8.cmd_flag_d.do_it = 0xe1;    // 上位机写入参数 E1帧处理
                Ano_V8.cmd_flag_d.check_arg = arg; // 传递给指针,直接处理
                Ano_V8.cmd_flag_d.E1 = 1;          // 写入参数ID 需要返回校验帧
            }

            if (*(arg + 3) == 0xe2) // 参数信息返回 不需要返回校验帧
            {
                Ano_V8.cmd_flag_d.E2 = 1; // 发送参数信息
            }

            if (*(arg + 3) == 0xe3) // 设备信息返回 不需要返回校验帧
            {
            }
            if (*(arg + 3) == 0xf0) // 固件升级
            {

                Ano_V8.cmd_flag_d.check_arg = arg; // 传递给指针
                Ano_V8.cmd_flag_d.F0 = 1;          // 发送升级命令帧
            }
        }
    }
}